#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
IR 函数节点定义
"""

import ast
from dataclasses import dataclass, field
from typing import Any, Dict, List, Optional, Iterator
from ..base import IRNode, Parameter
from ..statements import IRStmtBlock
from ...symbol_meta import Symbol, SymbolKind, Signature
from ...type_system import parse_type


@dataclass
class IRFunctionNode(IRNode):
    """IR函数节点"""

    name: str = field(default="")
    source_line: int = field(default=0)
    decorators: List[Dict[str, Any]] = field(default_factory=list)
    doc: str = field(default="")
    params: List[Parameter] = field(default_factory=list)
    return_type: Optional[str] = field(default=None)
    body: IRStmtBlock = field(default_factory=IRStmtBlock)
    is_async: bool = field(default=False)
    is_static: bool = field(default=False)

    # 闭包捕获变量（嵌套函数的核心特性，与 IRLambda 统一）
    captured_vars: List[str] = field(default_factory=list)

    # 模板参数：从签名中推导的TypeVar（如T, K, V）
    # 延迟初始化，首次访问时通过_get_template_params()计算
    _template_params: Optional[List[str]] = field(default=None, init=False, repr=False)

    # 类属性
    node_type: str = "function"

    @property
    def template_params(self) -> List[str]:
        """获取模板参数（延迟初始化）"""
        if self._template_params is None:
            self._template_params = self._extract_template_params_from_signature()
        return self._template_params

    def creates_scope(self) -> bool:
        """函数节点总是创建作用域"""
        return True

    def get_child_nodes(self) -> Iterator[IRNode]:
        """获取所有子节点"""
        # 函数参数
        if self.params:
            for param in self.params:
                yield param
        # 函数体语句块
        yield self.body
        yield from super().get_child_nodes()

    def format_cpp_params(self) -> str:
        """格式化函数参数列表用于函数声明"""
        if not self.params:
            return ""

        return ", ".join(
            [f"{param.get_cpp_type()} {param.name}" for param in self.params]
        )

    def get_cpp_return_type(self) -> str:
        """获取函数的C++返回类型

        优先使用type_inference阶段推导并缓存的类型信息，
        确保代码生成阶段不进行类型推导。
        """
        cpp_return_type = self.get_extension_param("cpp_return_type")
        if cpp_return_type is not None:
            return cpp_return_type

        # 如果 return_type 是 "None"，直接返回 "void"
        if self.return_type == "None":
            return "void"

        return self.return_type or "void"

    def create_signature(self) -> Signature:
        """从函数节点直接创建签名（不依赖类型推导）

        通过检查模块中定义的 TypeVar 来识别模板参数。

        Returns:
            Signature: 函数签名对象
        """
        # 优先使用IR构建阶段已提取的template_params
        # 这在build_from_ast时通过_extract_template_params_from_signature()提取
        if self.template_params:
            template_params = self.template_params
            # 构建模板参数映射（用于参数位置追踪）
            template_param_mapping = {}
            for i, param in enumerate(self.params):
                param_type = param.type_annotation or "Any"
                if param_type in template_params:
                    if param_type not in template_param_mapping:
                        template_param_mapping[param_type] = {}
                    template_param_mapping[param_type][f"param_{i}"] = i
        else:
            # 如果IR阶段没有提取到（可能是旧代码或特殊情况）
            # 使用extension_param作为备用
            template_params = []
            template_param_mapping = {}

            extracted_template_params = self.get_extension_param("template_params")
            if extracted_template_params:
                template_params = extracted_template_params

        # 提取参数类型和参数名
        param_types = []
        args = []
        for param in self.params:
            param_type_str = param.type_annotation or "Any"
            param_type = self._normalize_type_name(param_type_str)
            param_types.append(param_type)
            args.append(param.name)

        # 提取返回类型
        inferred_type = self.get_extension_param("inferred_type")
        if inferred_type and inferred_type.return_type:
            return_type_str = str(inferred_type.return_type)
        else:
            return_type_str = self.return_type or "None"

        # 规范化返回类型名称
        return_type = self._normalize_type_name(return_type_str)

        # 提取 param_overrides（如果有 @mcpy_param_override 注解）
        param_overrides = self.get_extension_param("param_overrides")

        # 提取 callback_path（如果有 @mcpy_callback 注解）
        callback_path = self.get_extension_param("callback_path")

        # 提取 emit_template（如果有 @mcpy_emit_template 注解）
        emit_template = self.get_extension_param("emit_template")

        # 提取 is_macro（如果有 @mcpy_macro 注解）
        is_macro = self.get_extension_param("is_macro", False)

        sig = Signature(
            function_name=self.name,
            param_types=param_types,
            return_type=return_type,
            template_params=template_params,
            template_param_mapping=template_param_mapping,
            callback_path=callback_path,
            emit_template=emit_template or "",
            args=args,
            is_method=False,
            is_macro=is_macro,
        )

        # 应用 param_overrides
        if param_overrides:
            sig.param_overrides = param_overrides

        return sig

    def _normalize_type_name(self, type_str: str) -> str:
        """规范化类型名称，将类型别名转换为规范名称"""
        # 去掉前向引用的引号（单引号或双引号）
        type_str = type_str.strip()
        if (type_str.startswith("'") and type_str.endswith("'")) or (
            type_str.startswith('"') and type_str.endswith('"')
        ):
            type_str = type_str[1:-1]

        type_info = parse_type(type_str, self)
        if type_info:
            return str(type_info)
        else:
            return type_str

    def _get_module_typevars(self) -> set:
        """获取模块中定义的所有 TypeVar 名称

        通过调用模块的 get_module_typevars() 方法获取（带缓存）。
        根据 Python 规范，TypeVar 必须在模块级别定义。

        Returns:
            set: TypeVar 名称集合
        """
        module = self.get_ir_module()
        if not module:
            return set()

        return module.get_module_typevars()

    def new_symbol(self) -> "Symbol":
        """创建函数的符号

        注意：签名创建被延迟到真正需要时（延迟初始化模式）
        这避免了在 build_symbol_cache 阶段的循环依赖问题
        """
        # 获取所属模块信息
        ir_module = self.get_ir_module()
        module_name = ir_module.module_full_name if ir_module else None

        symbol = Symbol(
            self.name,
            SymbolKind.FUNCTION,
            ir_node=self,
            module=module_name,
        )

        return symbol

    def get_local_symbols(self) -> Iterator[Symbol]:
        """获取函数中定义的所有本地符号

        Returns:
            本地符号的迭代器
        """

        # 参数符号
        for param in self.params:
            yield param.get_symbol()

        # 函数体中的局部变量
        if self.body:
            for symbol in self.body.get_local_symbols():
                yield symbol

    def _extract_template_params_from_signature(self) -> List[str]:
        """从函数签名中提取模板参数（延迟初始化）

        通过类型系统递归检查参数和返回类型中是否使用了模块级TypeVar。
        支持嵌套泛型类型，如 future[T], dict[K, V], Callable[[T], R]。

        延迟调用：首次访问template_params property时才执行，确保模块完全构建。

        Returns:
            模板参数名列表，如 ['T'] 或 ['K', 'V']
        """
        from mcpy.type_system import extract_typevars_from_type_string

        # 获取模块中定义的所有 TypeVar（符号系统查找）
        module_typevars = self._get_module_typevars()
        if not module_typevars:
            return []

        template_params = []

        # 从返回类型中提取TypeVar（递归，通过类型系统）
        if self.return_type:
            typevars = extract_typevars_from_type_string(
                self.return_type, module_typevars, node=self
            )
            for tv in typevars:
                if tv not in template_params:
                    template_params.append(tv)

        # 从参数类型中提取TypeVar（递归，通过类型系统）
        for param in self.params:
            if param.type_annotation:
                typevars = extract_typevars_from_type_string(
                    param.type_annotation, module_typevars, node=self
                )
                for tv in typevars:
                    if tv not in template_params:
                        template_params.append(tv)

        return template_params

    def build_from_ast(self, node: ast.FunctionDef | ast.AsyncFunctionDef) -> None:
        """从 AST 函数定义节点构建 IR 函数节点内容

        Args:
            node: AST 函数定义节点
        """
        super().build_from_ast(node)

        # 提取参数信息
        params = []
        # Python AST: 默认值在 node.args.defaults 中，但列表是右对齐的
        # 例如：def f(a, b=1, c=2): defaults = [1, 2]（a 没有默认值）
        num_args = len(node.args.args)
        num_defaults = len(node.args.defaults)
        first_default_idx = num_args - num_defaults  # 第一个有默认值的参数索引

        for i, arg in enumerate(node.args.args):
            # 计算当前参数是否有默认值
            default_value = None
            if i >= first_default_idx:
                default_idx = i - first_default_idx
                default_ast = node.args.defaults[default_idx]
                # 构建默认值的 IR 节点
                from mcpy.ir.expressions import build_expr_from_ast

                default_value = build_expr_from_ast(default_ast, parent=self)

            param = Parameter(
                name=arg.arg,
                type_annotation=(ast.unparse(arg.annotation) if arg.annotation else ""),
                default_value=default_value,
                parent=self,
            )
            params.append(param)

        # 提取装饰器信息
        decorators = []
        for decorator in node.decorator_list:
            if isinstance(decorator, ast.Name):
                # 简单装饰器：@decorator_name
                decorators.append({"name": decorator.id, "args": [], "kwargs": {}})
            elif isinstance(decorator, ast.Call):
                # 带参数的装饰器：@decorator_name(args)
                decorator_name = ""
                if isinstance(decorator.func, ast.Name):
                    decorator_name = decorator.func.id
                elif isinstance(decorator.func, ast.Attribute):
                    decorator_name = ast.unparse(decorator.func)

                # 提取位置参数
                args = []
                for arg in decorator.args:
                    if isinstance(arg, ast.Constant):
                        args.append(arg.value)
                    else:
                        args.append(ast.unparse(arg))

                # 提取关键字参数
                kwargs = {}
                for keyword in decorator.keywords:
                    if isinstance(keyword.value, ast.Constant):
                        kwargs[keyword.arg] = keyword.value.value
                    else:
                        kwargs[keyword.arg] = ast.unparse(keyword.value)

                decorators.append(
                    {"name": decorator_name, "args": args, "kwargs": kwargs}
                )
            else:
                # 其他复杂装饰器形式
                decorators.append(
                    {"name": ast.unparse(decorator), "args": [], "kwargs": {}}
                )

        # 设置函数节点属性
        self.name = node.name
        self.source_line = getattr(node, "lineno", 0)
        self.decorators = decorators
        self.params = params
        self.return_type = ast.unparse(node.returns) if node.returns else None
        # 保存原始返回类型注解信息用于严格类型检查
        self.set_extension_param(
            "original_return_annotation",
            ast.unparse(node.returns) if node.returns else None,
        )
        self.is_async = isinstance(node, ast.AsyncFunctionDef)
        self.doc = ast.get_docstring(node) or ""

        self.body = IRStmtBlock(parent=self)
        self.body.build_from_ast(node.body)
